package org.example.start;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.example.annotation.Auth;
import org.example.annotation.EnableAutoRegister;
import org.example.feign.RegisterFeign;
import org.example.pojo.AuthInfo;
import org.example.pojo.Respond;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


@Component
@Slf4j
@SuppressWarnings("ALL")
public class AuthCheck implements CommandLineRunner, ApplicationContextAware {

    private ApplicationContext applicationContext;

    private Environment environment;

    private String centreURL;

    private String retry;

    @Resource
    RegisterFeign registerFeign;
    @Override
    public void run(String... args) throws UnknownHostException {
        int counte = Integer.parseInt(retry);
        log.info("鉴权信息注册 ---> "+centreURL);
        Map<String, Object> enableAutoRegisters = applicationContext.getBeansWithAnnotation(EnableAutoRegister.class);

        Set<Map.Entry<String, Object>> entries = enableAutoRegisters.entrySet();

        for(Map.Entry<String,Object> entry:entries){
            String router = getRouter(entry.getValue());

            Method[] declaredMethods = entry.getValue().getClass().getDeclaredMethods();

            for(Method method:declaredMethods){
                AuthInfo authInfo = getAuthInfo(method);
                String path = getPath(method);

                String address = router+path;

                Respond<String> register = null;

                try {
                    register = registerFeign.register(address, authInfo);
                }catch (Exception exception){
                    log.error("无法连接鉴权中心");
                    continue;
                }

                log.info(register.toString());

                if(register.getStatusCode()!=1) {
                    log.error(address + ":注册出现未知错误");
                    retry(registerFeign,address,authInfo,counte);
                }
                else
                    log.info(address+"--->"+centreURL+":注册成功");
            }

        }
    }

    private void retry(RegisterFeign registerFeign,String router,AuthInfo authInfo,int c){
        int count = c;
        while (c>0){
            log.info("retry: "+c+"to register--->"+centreURL);
            c--;
            Respond<String> register = registerFeign.register(router, authInfo);
            if(register.getStatusCode()==1){
                log.info("retry successful--->"+centreURL);
                return;
            }

        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        this.environment = applicationContext.getEnvironment();
        this.centreURL = environment.getProperty("auth.centre.url");
        this.retry = environment.getProperty("auth.centre.retry");
    }

    private String AddressAndPort() throws UnknownHostException {
        String address = InetAddress.getLocalHost().getHostAddress();
        String port = environment.getProperty("server.port");

        return "http://"+address+":"+port;
    }

    private String getRouter(Object controller) throws UnknownHostException {
        Class<?> aClass = controller.getClass();
        RequestMapping requestMapping = aClass.getDeclaredAnnotation(RequestMapping.class);
        return requestMapping.value()[0];
    }

    private AuthInfo getAuthInfo(Method method){
        Auth auth = method.getDeclaredAnnotation(Auth.class);
        HashSet<String> roles = new HashSet<>();
        for(String role: auth.roles())
            roles.add(role);
        AuthInfo authInfo = new AuthInfo(auth.enable(), auth.token(), null, roles, auth.level(),auth.authType());
        return authInfo;
    }

    private String getPath(Method method){
        RequestMapping requestMapping = method.getDeclaredAnnotation(RequestMapping.class);
        if(requestMapping!=null){
            return requestMapping.value()[0];
        }

        GetMapping getMapping = method.getDeclaredAnnotation(GetMapping.class);
        if(getMapping!=null)
            return getMapping.value()[0];

        PostMapping postMapping = method.getDeclaredAnnotation(PostMapping.class);
        if(postMapping!=null)
            return postMapping.value()[0];
        return "/";
    }
}
